<?php

/*
class Controller, base controller class
Copyright (C) 2011  Petr Čermák

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

require_once 'Request.php';
require_once 'Checker.php';
require_once 'Component.php';

class Controller extends Component{

    protected static $_request;
    private $preserve = false;
    private $initialized = false;
    protected $request = null;
    private $parameters = array();
    private $helpers = array();

    public static function _staticInitializer(){
        self::$_request = new Request();
    }

    public function __construct(){$this->request = new Request();}

    /**
     * Gets array of parameters that this controlles uses.
     * @return array  array of parameters
     */
    public function getUsedParameters(){return $this->parameters;}

    /**
     * Registers a helper for this Controller.
     * @param Helper $helper  Helper to be registered for this Controller.
     */
    public function addHelper(Helper $helper){
        $helper->setOwner($this);
        $this->helpers[] = $helper;
    }

    /**
     * Returns whether this controller's state will be preserved even if it's not currently displayed.
     * @return bool  true if preservation is enabled, otherwise false
     */
    public function isPreservationEnabled(){return $this->preserve;}

    /**
     * Sets whether this controller's state will be preserved even if it's not currently displayed.
     * @param bool $enabled  true if preservation should be enabled, otherwise false
     */
    public function setPreservationEnabled($enabled){$this->preserve = $enabled;}

    /**
     * Gets request object associated with this controller.
     * @return Request
     */
    public function getRequest(){return $this->request;}

    /**This method should be overloaded to initialize component.*/
    protected function init(){}

    /**This method should be overloaded to process request from user.*/
    protected function process(){}

    /**Initializes the controller*/
    public function initialize(){
        if(!$this->initialized){
            $this->request->setController($this);
            $this->init();
            $this->initialized = true;
        }
    }

    /**Processes all Helpers associated with this Controller*/
    public function processHelpers(){
        foreach($this->helpers as $helper)$helper->process();
    }

    /**Processes the request from user.*/
    public function processRequest(){
        $this->processHelpers();
        $this->process();
    }

    /**
     * Reserves parameter that this controller uses.
     * It is necessary to use this method when creating
     * reload addresses of this component from other component.
     */
    public function reserveParameter($name){
        Checker::checkString($name);
        if(!in_array($name, $this->parameters))$this->parameters[] = $name;
    }

    /**Reserves all parameters in the provided array*/
    public function reserveParameters($array){
        Checker::checkArray($array);
        foreach($array as $param)$this->reserveParameter($param);
    }

    public function createActionAddress($staticMethodName, $arguments){
        return Application::createActionAddress(get_class($this), $staticMethodName, $arguments);
    }

    /**
     * Creates an address for action of provided method name.
     * The purpose of action is to replace whole response to the user with
     * output of the action method. This behavior is necessary when AJAX
     * requests need to be handled by a component that is inside other component.
     * @return string  the created address
     */
    /*public function createActionAddress($methodName){
        Checker::checkString($methodName);
        $cn = 0;
        $address = '';
        $comp = $this;
        $owner = $this->getOwner();
        while($owner !== null){
            $address = "&amp;c$cn=".$comp->getName().$address;
            $comp = $owner;
            $owner = $comp->getOwner();
            $cn++;
        }
        $address = $_SERVER['PHP_SELF']."?cn=$cn&amp;action=$methodName$address";
        return $address;
    }*/

    /**
     * Creates a JavaScript representation of object containing url parameters
     * for selected action. This is necessary for using dojo xhr methods.
     * @return string  the created JavaScript object
     */
    /*public function createActionJsObject($methodName){
        Checker::checkString($methodName);
        $cn = 0;
        $obj = '';
        $comp = $this;
        $owner = $this->getOwner();
        while($owner !== null){
            $obj .= ", c$cn: ".'"'.$comp->getName().'"';
            $comp = $owner;
            $owner = $comp->getOwner();
            $cn++;
        }
        $obj = "{cn: $cn, action: \"$methodName\"$obj}";
        return $obj;
    }*/

    /**
     * Creates string containing HTML input tags with parameters for selected
     * action, this could be used in forms.
     * @return string  the created HTML inputs
     */
    /*public function createActionHtmlInputs($methodName){
        Checker::checkString($methodName);
        $cn = 0;
        $html = '';
        $comp = $this;
        $owner = $this->getOwner();
        while($owner !== null){
            $html .= "<input type='hidden' name='c$cn' value='".$comp->getName()."'>";
            $comp = $owner;
            $owner = $comp->getOwner();
            $cn++;
        }
        $html = "<input type='hidden' name='cn' value='$cn'><input type='hidden' name='action' value='$methodName'>".$html;
        return $html;
    }*/

    /**
     * Creates an address that reloads whole page with the same parameters.
     * If array of parameters is provided, then these are added to the address,
     * if parameter value in the array is null, and the parameter is present in
     * the address, the parameter will be deleted.
     * @return string the created address
     */
    public function createReloadAddress($param = array()){
        Checker::checkArray($param);

        $address = $_SERVER['PHP_SELF'];

        $urlParam = Application::getValidUrlParameters();

        if(empty($urlParam)){
            if(empty($param))return $address;
            $first = true;
            foreach($param as $name => $value){
                if($value !== null){
                    if($first){
                        $address .= "?$name=$value";
                        $first = false;
                    }
                    else $address .= "&amp;$name=$value";
                }
            }
            return $address;
        }
        
        $first = true;
        foreach($urlParam as $name => $value){
            if(array_key_exists($name, $param)){
                $v = $param[$name];
                unset($param[$name]);
            }
            else $v = $value;
            if($v !== null){
                if($first){
                    $address .= "?$name=$v";
                    $first = false;
                }
                else $address .= "&amp;$name=$v";
            }
        }

        foreach($param as $name => $value)
            if($value !== null)$address .= "&amp;$name=$value";
        
        return $address;
    }
}
Controller::_staticInitializer();
?>
